package org.dicr.util.jds.gui;

import java.awt.event.*;
import java.io.*;
import java.util.zip.*;

import javax.swing.text.*;

import org.dicr.event.*;
import org.dicr.gui.*;

import com.borland.dx.dataset.*;

/***********************************************************************************************************************
 * @author Igor A Tarasov me@dicr.dn.ua
 * @version 021202
 **********************************************************************************************************************/
public class DataDocumentEditorPanel extends DocumentEditorPanel implements ColumnAware {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	protected DataSet dataset = null;

	protected String columnName = null;

	protected DataListener dataListener = new DataListener();

	/*******************************************************************************************************************
	 * Конструктор
	 ******************************************************************************************************************/
	public DataDocumentEditorPanel() {
		try {
			jbInit();
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		}
	}

	/*******************************************************************************************************************
	 * Инициализация
	 ******************************************************************************************************************/
	private void jbInit() {
		this.editor.addFocusListener(new DocumentFocusListener());
	}

	/*******************************************************************************************************************
	 * Устанавливает источник данных
	 ******************************************************************************************************************/
	@Override
    public void setDataSet(DataSet dataSet) {
		if (this.dataset != dataSet) try {
			if (this.dataset != null) {
				this.dataset.removeAccessListener(this.dataListener);
				this.dataset.removeNavigationListener(this.dataListener);
			}
			this.dataset = dataSet;
			if (this.dataset != null) {
				this.dataset.addAccessListener(this.dataListener);
				this.dataset.addNavigationListener(this.dataListener);
				this.dataset.open();
			}
			updateDocument();
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		}
	}

	/*******************************************************************************************************************
	 * Возвращает источник данных
	 ******************************************************************************************************************/
	@Override
    public DataSet getDataSet() {
		return this.dataset;
	}

	/*******************************************************************************************************************
	 * Проверяет источник данных на корректность
	 ******************************************************************************************************************/
	protected boolean isValidDataSetState() {
		return (this.dataset != null && this.dataset.isOpen() && this.columnName != null && this.dataset.hasColumn(this.columnName) != null);
	}

	/*******************************************************************************************************************
	 * Устанавливает имя колонки
	 ******************************************************************************************************************/
	@Override
    public void setColumnName(String theColumnName) {
		if (this.columnName != theColumnName) {
			this.columnName = theColumnName;
			updateDocument();
		}
	}

	/*******************************************************************************************************************
	 * Возвращает имя колонки
	 ******************************************************************************************************************/
	@Override
    public String getColumnName() {
		return this.columnName;
	}

	/*******************************************************************************************************************
	 * Обновление документа при смене данных
	 ******************************************************************************************************************/
	protected void updateDocument() {
		this.setCursor(GuiMisc.CURSOR_WAIT);
		try {
			boolean loaded = false;
			if (isValidDataSetState() && !this.dataset.isNull(this.columnName)) try {
				InputStream in = this.dataset.getInputStream(this.columnName);
				in.reset();
				if (in.available() > 0) {
					GZIPInputStream zin = new GZIPInputStream(in);
					int contentLenth = zin.read();
					byte[] contentBytes = new byte[contentLenth];
					zin.read(contentBytes, 0, contentLenth);
					String contentStr = new String(contentBytes);
					this.editor.setContentType(contentStr);
					this.docIO.loadDocument(zin, this.editor);
					loaded = true;
				}
			} catch (Exception ex) {
				DicrExceptionHandler.handleException(ex, this);
			}
			if (!loaded) this.docIO.initDocument(this.editor);
			fireChangeEvent();
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		}
		this.setCursor(GuiMisc.CURSOR_DEFAULT);
	}

	/*******************************************************************************************************************
	 * Обновление данных в базу данных при смене текста в редакторе
	 ******************************************************************************************************************/
	protected void updateData() {
		this.setCursor(GuiMisc.CURSOR_WAIT);
		try {
			if (isValidDataSetState()) {
				InputStream in = null;
				if (this.editor.getDocument().getLength() > 0) try {
					ByteArrayOutputStream bou = new ByteArrayOutputStream();
					GZIPOutputStream zou = new GZIPOutputStream(bou);
					String contentStr = this.editor.getContentType();
					byte[] contentBytes = contentStr.getBytes();
					zou.write(contentBytes.length);
					zou.write(contentBytes);
					this.docIO.saveDocument(zou, this.editor);
					zou.finish();
					zou.flush();
					bou.flush();
					zou.close();
					bou.close();
					byte[] data = bou.toByteArray();
					in = new ByteArrayInputStream(data);
					in.mark(data.length);
				} catch (Exception ex) {
					DicrExceptionHandler.handleException(ex, this);
				}
				this.dataset.setInputStream(this.columnName, in);
			}
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		}
		this.setCursor(GuiMisc.CURSOR_DEFAULT);
	}

	/*******************************************************************************************************************
	 * Загрузка документа (переопределение)
	 ******************************************************************************************************************/
	@Override
	public boolean loadDocument() throws IOException, BadLocationException {
		boolean ret = false;
		if (super.loadDocument()) {
			updateData();
			ret = true;
		}
		return ret;
	}

	/*******************************************************************************************************************
	 * Очистка документа (переопределение)
	 ******************************************************************************************************************/
	@Override
	public void clearDocument() {
		super.clearDocument();
		updateData();
	}

	/*******************************************************************************************************************
	 * Установка документа (переопределение)
	 ******************************************************************************************************************/
	@Override
	public void setDocument(Document doc) {
		if (this.editor.getDocument() != doc) {
			super.setDocument(doc);
			updateData();
		}
	}

	/*******************************************************************************************************************
	 * ######################################################################### Слушатель фокуса документа
	 * #########################################################################
	 ******************************************************************************************************************/
	class DocumentFocusListener extends FocusAdapter {
		/***************************************************************************************************************
		 * Обработка фокуса поля редактирования
		 **************************************************************************************************************/
		@Override
		public void focusLost(FocusEvent e) {
			try {
				updateData();
			} catch (Exception ex) {
				DicrExceptionHandler.handleException(ex, this);
			}
		}
	}

	/*******************************************************************************************************************
	 * ######################################################################### Слушатель данных
	 * #########################################################################
	 ******************************************************************************************************************/
	class DataListener implements NavigationListener, AccessListener {
		/***************************************************************************************************************
		 * Обработчик событий навигации по данным
		 **************************************************************************************************************/
		@Override
        public void navigated(NavigationEvent event) {
			try {
				updateDocument();
			} catch (Exception ex) {
				DicrExceptionHandler.handleException(ex, this);
			}
		}

		/***************************************************************************************************************
		 * Обработчик событий доступа к данным
		 **************************************************************************************************************/
		@Override
        public void accessChange(AccessEvent event) {
			try {
				updateDocument();
			} catch (Exception ex) {
				DicrExceptionHandler.handleException(ex, this);
			}
		}
	}
}
